package com.dyna.demo.limiter;

import com.dyna.aop.annotation.Idempotent;
import com.dyna.aop.annotation.RequestRedisLimiter;
import com.dyna.core.aop.annotation.RequestLimiter;
import com.dyna.core.exception.CustomException;
import com.dyna.domain.resp.R;
import com.dyna.domain.resp.ResultCode;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.Semaphore;

@Api("demo模块/demo/限流")
@RestController
@AllArgsConstructor
@RequestMapping("/limiter")
public class LimiterController {

    private final LimiterService limiterService;

    @ApiOperation("信号量限流")
    @RequestMapping("/semaphore")
    public R<Integer> semaphore() {
        Integer semaphore = limiterService.semaphore();
        return R.isSuccess(semaphore);
    }

    @ApiOperation("获取信号量超时")
    @RequestMapping("/timeoutSemaphore")
    public R<Object> timeoutSemaphore() {
        return R.data(limiterService.timeoutSemaphore());
    }

    @RequestLimiter
    @ApiOperation("信号量注解限流")
    @RequestMapping("/semaphoreAnnotation")
    public R<Object> semaphoreAnnotation() {
        return R.success(ResultCode.SUCCESS);
    }

    @RequestRedisLimiter
    @ApiOperation("Redis注解限流")
    @RequestMapping("/redisAnnotationLimiter")
    public R<Object> redisAnnotationLimiter() {
        return R.success(ResultCode.SUCCESS);
    }

    @Idempotent
    @ApiOperation("测试redis幂等")
    @RequestMapping("/testIdempotent")
    public R<Object> testIdempotent() {
        return R.success(ResultCode.SUCCESS);
    }

}

@Slf4j
@Service
class LimiterService {

        private static final Semaphore permit = new Semaphore(1, true);
        private final Semaphore permit2 = new Semaphore(1, true);
    private static Integer count = 0;

    /**
     * 控制住了
     */
    public Integer semaphore() {
        try {
            // 获取许可证
            permit.acquire();
            log.info("执行业务");
            Thread.sleep(10000);
//            count ++;
//            if ((count % 2) == 0) {
//                int i = 1 / 0;
//            }
        } catch (Exception e) {
            log.error("业务逻辑出错了...\n",e);
        }finally {
            // 释放许可证
            log.info("释放许可证...");
            permit.release();
        }
        return 1;
    }

    public Integer timeoutSemaphore() {
        try {
            log.info("获取锁之前...");
            if (permit.tryAcquire(2)) {
                log.info("获取到了锁，并且执行了业务...");
                Thread.sleep(5000);
            }else {
                log.error("获取许可证失败");
                throw new CustomException("获取许可证失败");
            }
        } catch (Exception e) {
            throw new CustomException("获取许可证失败");
        }finally {

            permit.release(1);
        }
        return 1;
    }

}